#include <stdio.h>
#include <stdlib.h>
#include "linkedlist.h"


static ThrdCtlBlk *notFound;
static ThrdCtlBlk *noneLeft;

/*
*
* Initializes linked list
* as well as two TCBs for error return
*
*/
struct linkedlist *list_init(){
  notFound = (ThrdCtlBlk *)malloc(sizeof(ThrdCtlBlk));
  notFound->tid = -1;
  noneLeft = (ThrdCtlBlk *)malloc(sizeof(ThrdCtlBlk));
  noneLeft->tid = -2;
  struct linkedlist *list = (struct linkedlist *)malloc(sizeof(struct linkedlist));
  list->size = 0;
  return list;
}

/*
* Look at top Tid without changing
*/
ThrdCtlBlk *peek(struct linkedlist *list){
  return list->headNode->thisBlk;
}
/*
*
* Frees global TCBs
*
*/
void freeGlobals(){
  free(notFound);
  free(noneLeft);
}

/*
*
* Frees list and all nodes in it
*
*/
void freeList(struct linkedlist *list, int freeBlk){
  freeGlobals();
  int i;
  struct threadNode *node = list->headNode;
  if (list->size == 1 || list->size == 0) {
    free(node);
    free(list);
    return;
  }
  struct threadNode *nextNode = node->nextNode;
  for (i = 0; i< list->size-1; i++){
    if (freeBlk) {
      free(node->thisBlk->context->uc_stack.ss_sp);
      free(node->thisBlk->context);
      free(node->thisBlk);
    }
    free(node);
    node = nextNode;
    nextNode = node->nextNode;  
  }
  free(node);
  free(list);
  return;
}

int threadForTid (struct linkedlist *list, Tid tid)
{
	if (list->size == 0)
		return 0;
	struct threadNode *currentThread = list->headNode;
	while (currentThread)
	{
		if (currentThread->thisBlk->tid == tid)
		{
			return 1;
		}
		currentThread = currentThread->nextNode;
	}
	return 0;
}

/*
*
* Pushes TCB onto que
*
*/
void append(struct linkedlist *list, ThrdCtlBlk *newnode){
  if (list->size == 0){
    list->headNode = (struct threadNode *)malloc(sizeof(struct threadNode));
    list->headNode->thisBlk = newnode;
    list->size = 1;
  }
  else {
    struct threadNode *node = (struct threadNode *)malloc(sizeof(struct threadNode));
    struct threadNode *head = list->headNode;
    node->thisBlk = newnode;
    int i = 1;
    while (i < list->size){
      head = head->nextNode;
      i = i + 1;
    }
    head->nextNode = node;
    list->size = list->size + 1;
    return;
  }
}

/*
*
* Prints Tids of all TCBs in list
*
*/
void printList(struct linkedlist *list){
  if (list->size == 0) { printf("NULL\n"); return; }
  struct threadNode *head = list->headNode;
  int i=1;
  while (i < list->size){
    printf("%d, ", head->thisBlk->tid);
    head = head->nextNode;
    i = i+1;
  }
  printf("%d\n", head->thisBlk->tid);
}

ThrdCtlBlk *removeNode(struct linkedlist *list, Tid tid){
  //set up result for failure
  //printf("removed\n");
  if (list->size == 0) {
   return noneLeft;
   }

  struct threadNode *head = list->headNode;
  ThrdCtlBlk *result = head->thisBlk;
  int found = 0;

  //if found at beginning
  if (result->tid == tid){
    list->headNode = head->nextNode;
    free(head);
    list->size--;
    return result;
  }

  //if found somewhere in middle or end
  struct threadNode *nextToHead = head->nextNode;
  int i = 0;
  Tid thistid;
  while (i < list->size){
    thistid = nextToHead->thisBlk->tid;
    if (thistid == tid){
      found = 1;
      if (i < list->size-1) head->nextNode = nextToHead->nextNode;
      result = nextToHead->thisBlk;
      free(nextToHead); 
      list->size--;
      return result;
    } 
    if (i < list->size-1) head = head->nextNode;
    if (i < list->size-2) nextToHead = head->nextNode;
    i++;
  }
  if (!found) return notFound;
  return result; 
}

/*
*
* Pops the queue with FIFO system
*
*/
ThrdCtlBlk *pop(struct linkedlist *list){
  struct threadNode *head = list->headNode;
  ThrdCtlBlk *result;
  if (list->size == 0) {
    return noneLeft;
  }
  result = head->thisBlk;
  if (list->size == 1){
    free(head);
    list->size = 0;
    return result;
  }
  list->headNode = head->nextNode;
  list->size = list->size - 1;
  free(head);
  return result;
  
}

/**
void main(){
  struct linkedlist *list = list_init();

  ThrdCtlBlk *blk = (ThrdCtlBlk *)malloc(sizeof(ThrdCtlBlk));
  ThrdCtlBlk *blk2 = (ThrdCtlBlk *)malloc(sizeof(ThrdCtlBlk));
  blk2->tid = 3;
  blk->tid = 2;
  append(list,blk2);
  append(list,blk);  
  append(list,blk);
  append(list,blk);
  append(list,blk2);
  append(list,blk);
  printList(list);
 // removeNode(list,3);
  printList(list);
 // removeNode(list,3);
  printList(list);
  append(list,blk);
  append(list,blk);
  pop(list);
  append(list,blk);;
  append(list,blk2);;
  pop(list);
  append(list,blk);
  printList(list);
 // removeNode(list,3);
  printList(list);
  printf("%d\n", list->size);

  //append(list,blk);
  freeList(list,0);
  free(blk);
  free(blk2);
  

} **/







